/* ----------------------------------------------------------------------------------------------------------------
 * Entity
 * ----------------------------------------------------------------------------------------------------------------
 */
package pure.engine.entity 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	import pure.debug.ErrorKai;
	import pure.engine.core.VisibleCore;
	import pure.engine.renderer.AnimationRenderer;
	import pure.engine.renderer.IAnimation;
	import pure.engine.renderer.IRenderer;
	import pure.engine.renderer.IShape;
	import pure.engine.renderer.IText;
	import pure.engine.renderer.Renderer;
	import pure.engine.renderer.ShapeRenderer;
	import pure.engine.renderer.TextRenderer;
	import pure.engine.status.IStatus;
	import pure.engine.system.ProcessManager;
	import pure.engine.system.ns_despair;
	import pure.engine.world.WorldContent;

	use namespace ns_despair;
		

	/**
	 * @internal
	 * 
	 * 实体
	 * 
	 * @author ＃Pure
	 * @see IEntity
	 * 
	 */
public class Entity extends VisibleCore implements IEntity
{        
	public function Entity()
	{
		m_x = m_y = 0;
		m_statusMap     =  { };
		m_rendererList  =  new Vector.<Renderer>();
		_worldRect      =  new Rectangle();
		m_interactive    =  true;
		m_eventDispatcher = new EventDispatcher();
	}
	
	
	
	
	//======================
	// Member
	//======================

	
	ns_despair var m_id:int;
	
	ns_despair var m_layer:int;
	
	ns_despair var m_worldContent:WorldContent;

	ns_despair var m_rendererList:Vector.<Renderer>;
	
	ns_despair var m_numRenderer:int;
	
	ns_despair var m_statusMap:Object;

	ns_despair var _worldRect:Rectangle;

	ns_despair var m_alive:Boolean, m_interactive:Boolean;
	
	ns_despair var m_mirror:BitmapData;
	
	ns_despair var m_eventDispatcher:EventDispatcher;
	
	

	//======================
	// Cached
	//======================
	
	ns_despair var _cachedStatusName:String;
	
	ns_despair var m_bufferDirty:Boolean;    // 残像变化
	
	ns_despair var mirrorExisted:Boolean;    // 残像是否已存在于监控器
	
	ns_despair var m_entityDirty:Boolean;    // 残像是否被重绘
	
	ns_despair var _realX:Number, _realY:Number;
	
	
	ns_despair static var cachedArray:Array = [];

	ns_despair static var cachedMatrix:Matrix = new Matrix();
	
	ns_despair static var cachedColorTransform:ColorTransform = new ColorTransform();
	
	
	
	

	
	public function move(wx:Number, wy:Number):void
	{
		if (m_x != wx)    m_x  =  wx;
		if (m_y != wy)    m_y  =  wy;
	}

	
	public function offset(offsetX:Number, offsetY:Number):void 
	{
		if (offsetX == 0 && offsetY == 0)  return;
		
		m_x  +=  offsetX;
		m_y  +=  offsetY;
	}

	
	public function kill():void
	{
		var i:int;
		var R:Renderer
		
		if (!m_alive)  return;
		
		super.destroy();
		EntityManager.unregister(this);
		
		for (i = m_numRenderer - 1; i >= 0; i--)
		{
			R = m_rendererList[i];
			R.destroy();
		}
		
		m_rendererList.length  =  0;
		m_numRenderer          =  0;
		m_range                =  NaN;
		
		clearAllStatus();
		
		if(m_mirror)
		{
			m_mirror.dispose();
			m_mirror = null;
		}
		
		m_x = m_y = 0;
		m_visible      =  false;
		m_rangeDirty    =  false;
		m_bufferDirty   =  false;
		mirrorExisted  =  false;
		m_alive        =  false;
	}
	
	
	
	
	
	//======================
	// Renderer !!
	//======================
	
	public function createAnimationRenderer(section:String = null, name:String = null, isRealRenderer:Boolean = false):IAnimation
	{
		var R:AnimationRenderer;
		
		R = new AnimationRenderer();
		R.setSection(section);
		_addRenderer(R, name, isRealRenderer)
		return R;
	}
	
	
	public function createShapeRenderer(offsetX:Number = 0, offsetY:Number = 0, name:String = null, isRealRenderer:Boolean = false):IShape
	{
		var R:ShapeRenderer;
		
		R = new ShapeRenderer(offsetX,offsetY);
		_addRenderer(R, name, isRealRenderer)
		return R;
	}
	
	
	public function createTextRenderer(width:Number,
									height:Number,
									text:String, 
									name:String = null,
									offsetX:Number = 0, offsetY:Number = 0,
									isRealRenderer:Boolean = false):IText
	{
		var R:TextRenderer;
		
		R = new TextRenderer(width, height, text, offsetX, offsetY);
		_addRenderer(R, name, isRealRenderer)
		return R;
	}
	
	
	
	public function get headRenderer():IRenderer { return m_rendererList[0]; }
	public function get tailRenderer():IRenderer { return m_rendererList[m_numRenderer - 1]; }
	public function getRenderer(name:String):IRenderer 
	{
		var i:int;
		for (i = 0; i < m_numRenderer; i++) 
		{
			if (m_rendererList[i].m_name == name) 
			{
				return m_rendererList[i];
			}
		}
		throw new ErrorKai(this, 'getRenderer', '获取不存在的渲染器:' + name);
	}
	
	
	

	
	//======================
	// Status !!
	//======================
	
	public function addStatus(S:IStatus, name:String = 'S'):void
	{
		if (name == null || name == '')
		{
			throw new Error('Entity - ＃addStatus - 状态名称不可为null');
		}
		
		S.entity           =  this;
		S.absorb();
		m_statusMap[name]  =  S;
		_cachedStatusName  =  name;
	}
	
	
	public function removeStatus(name:String):void 
	{
		var S:IStatus;
		
		S = m_statusMap[name];
		S.exit();
		delete m_statusMap[name];
	}

	
	public function getStatus(name:String = null):IStatus
	{
		if (name == null || name == '')
		{
			return m_statusMap[_cachedStatusName];
		}
		return m_statusMap[name];
	}
	
	
	public function clearAllStatus():void
	{
		for (var n:String in m_statusMap)
		{
			removeStatus(n);
		}
	}


	
	
	
	//======================
	// Event Dispatcher
	//======================

	
	// 发送
	public function dispatchEvent (event:Event) : Boolean
	{
		return m_eventDispatcher.dispatchEvent(event);
	}
	
	
	// 侦听
	public function addEventListener (type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false) : void
	{
		m_eventDispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
	}
	
	
	// 移除
	public function removeEventListener (type:String, listener:Function, useCapture:Boolean = false) : void
	{
		m_eventDispatcher.removeEventListener(type, listener, useCapture);
	}
	
	
	// 查找
	public function hasEventListener (type:String) : Boolean
	{
		return m_eventDispatcher.hasEventListener(type);
	}
	
	
	// 根查找
	public function willTrigger (type:String) : Boolean
	{
		return m_eventDispatcher.willTrigger(type);
	}
	
	
	
	

	//======================
	// Property
	//====================== 
		
	
	public function get name():String { return m_name; }
	public function get id():int { return m_id; }
	public function get worldContent():WorldContent { return m_worldContent; }

	
	public function get interactive():Boolean { return m_interactive; }
	public function set interactive(b:Boolean):void { m_interactive = b; }


	public function get x():Number { return m_x; }
	public function set x(v:Number):void { m_x = v; }
	
	
	public function get y():Number { return m_y; }
	public function set y(v:Number):void { m_y = v; }
	
	
	/**
	 * 实体的弧度体现了实体本身的朝向，并非某个渲染器的朝向.
	 * 该属性的意义体现在缓存实体的弧度值，当它改变时会发送一个变化事件.
	 * 
	 * <Hint> 该属性并不与渲染相关联，完全的抽象属性.
	 */
	override public function set angle(v:Number):void 
	{ 
		if (m_angle != v)
		{
			m_angle = v// < 0 ? v + TWO_PI : v;
			//m_eventDispatcher.dispatchEvent(
		}
	}
	
	
	public function get realRect():Rectangle
	{
		m_realRect.x = _realX + m_x;
		m_realRect.y = _realY + m_y;
		return m_realRect;
	}

	
	public function get worldRect():Rectangle
	{
		_worldRect.x = m_x - m_range;
		_worldRect.y = m_y - m_range;
		return _worldRect; 
	}

	
	
	
	/* ----------------------------------------------------------------------------------------------------------------------
	 * ★★★★★★★★★★★★★★★★  private  ★★★★★★★★★★★★★★★★
	 * ----------------------------------------------------------------------------------------------------------------------
	 */
	
	

	
	
	/**
	 * @internal
	 * 
	 * 更新渲染器
	 * 
	 * @param elaspedT
	 * 
	 * @see IWorld - ＃updateAllRenderers
	 */
	ns_despair function updateRenderer(elapsedT:Number):void
	{	
		var R:Renderer;
		var i:int;
		
		m_entityDirty = false;
		
		// 更新渲染器
		for (i = 0; i < m_numRenderer; i++) 
		{
			R = m_rendererList[i];
			if(R.visible)
			{
				R.update(elapsedT);
				
				if (R.m_rangeDirty)
				{
					R.m_rangeDirty  =  false;
					m_rangeDirty   =  true;
				}
				
				if (R.m_bufferDirty)
				{
					R.m_bufferDirty  =  false;
					m_bufferDirty   =  true;
				}
			}
		}
		
		// 面积变化
		if(m_rangeDirty)
		{
			_checkMirrorAndRedraw();
			m_rangeDirty = false;
		}
		
		// 残像重绘
		if (m_bufferDirty)
		{
			m_mirror.fillRect(m_mirror.rect, 0x0);
			for (i = 0; i < m_numRenderer; i++) 
			{
				_drawRenderer(m_rendererList[i]);
			}
			
			// 滤镜
			if (m_numFilter)
			{
				for (i = 0; i < m_numFilter; i++)
				{
					m_mirror.applyFilter(m_mirror, m_mirror.rect, cachedZeroPoint, m_filterList[i]);
				}
			}
			
			m_bufferDirty   =  false;
			m_entityDirty  =  true;
		}
	}
	
	
	private function _addRenderer(R:Renderer, name:String, isRealRenderer:Boolean):void
	{
		R.m_name = name;
		m_rendererList.push(R);
		m_numRenderer++;
		if (isRealRenderer)
		{
			if (R.m_realRect)
			{
				m_realRect  =  R.m_realRect.clone();
				_realX     =  m_realRect.x;
				_realY     =  m_realRect.y;
			}
		}
	}
	
	
	/**
	 * 检查是否重绘残像
	 */
	private function _checkMirrorAndRedraw():void
	{
		var R:Renderer;
		var newRange:Number;
		var i:int;
		
		cachedArray.length = 0;
		for (i = 0; i < m_numRenderer; i++)
		{
			R = m_rendererList[i];
			if(R.visible && !isNaN(R.range))
			{
				cachedArray.push(R.range);
			}
		}
		cachedArray.sort(Array.NUMERIC | Array.DESCENDING);
		
		newRange = cachedArray[0];
		if (newRange != m_range)
		{
            if (m_mirror)  m_mirror.dispose();
			m_range            =  newRange;
			_worldRect.width   =  m_range;
			_worldRect.height  =  m_range;
			m_mirror           =  new BitmapData(m_range * 2, m_range * 2, true, 0x0);
		}
	}

	
	/**
	 * 绘制渲染器
	 * 
	 * @param R
	 */
	private function _drawRenderer(R:Renderer):void 
	{
		if (!R.visible)  return;
		
		var bmd:BitmapData;
		
		if (!R.m_transformDirty) 
		{
			cachedPoint.x  =  m_range + R.m_x;
			cachedPoint.y  =  m_range + R.m_y;
			bmd            =  R.bitmapData;
			
			if (R.m_alpha == 1)
				m_mirror.copyPixels(bmd, bmd.rect, cachedPoint, null, null, true);
			else
				m_mirror.copyPixels(bmd, bmd.rect, cachedPoint, R.alphaMask, null, true);
		}

		else
		{
			cachedMatrix.identity();
			if (R.ignoreAngle)
			{
				cachedMatrix.rotate(-R.angle);
			}
			cachedMatrix.translate(R.m_x, R.m_y);
			cachedMatrix.scale(R.scaleX, R.scaleY);
			cachedMatrix.rotate(R.angle);
			cachedColorTransform.alphaMultiplier = R.alpha;
			cachedMatrix.translate(m_range, m_range);
			m_mirror.draw(R.bitmapData, cachedMatrix, cachedColorTransform, null, null, true);
		}
	}
}
}
